Note that there are some explanatory texts on larger screens.

plurals
  1. POCanvas - good rendering practices?
    primarykey
    data
    text
    <p>I've been using the Canvas a lot lately for little Java games and i've noticed a lot of strange things can happen. For example, earlier today I created a little game in which the objective is to shoot enemy ships and get points. The game draws tiny 32x32 images on the screen (sometimes slightly bigger) and for a reason I am oblivious to, the game renders oddly.</p> <p>For example, my ship has a health bar above it's head:</p> <p><img src="https://i.stack.imgur.com/DWxHR.png" alt="enter image description here"></p> <p>As you can see by the image, the textures are really small. Despite this, the game lags and sometimes things render incorrectly like this for example:</p> <p><img src="https://i.stack.imgur.com/aeW4M.png" alt="enter image description here"></p> <p>If you look closely at the top of the health bar, you can see that it's been shifted upwards slightly, it puzzles me how his happens as all of my rendering is buffered.</p> <p>My rendering code:</p> <pre><code>public void render(){ BufferStrategy bs = getBufferStrategy(); if(bs == null){ createBufferStrategy(3); return; } Graphics2D g = (Graphics2D)bs.getDrawGraphics(); toDrawG.setColor(new Color(0x222222)); toDrawG.fillRect(0, 0, WIDTH, HEIGHT); draw((Graphics2D)toDrawG); g.drawImage(toDraw, 0, 0, null); g.dispose(); bs.show(); } public void draw(Graphics2D g){ if(Settings.planets){ renderer.renderPlanets(); } if(level != null){ for(int i = 0 ; i &lt; level.entityList.size(); i++){ if(level.entityList.get(i) != null){ level.entityList.get(i).render(renderer); } } } renderer.overlayString("Space Game", 20, 20, 24, 0xFFFFFF); renderer.overlayString(VERSION, 20, 50, 24, 0xFFFFFF); renderer.overlayString("FPS: " + renderer.fps, 20, 70, 24, 0xFFFFFF); renderer.overlayString("Ships spawned: " + level.shipsSpawned, 20, 90, 24, 0xFFFFFF); renderer.overlayString("Time Survived: " + level.time / 100 + "s", 20, 110, 24, 0xFFFFFF); renderer.overlayString("Physics FPS: " + fps, 20, 130, 24, 0xFFFFFF); if(currentGui != null){ currentGui.render(renderer); }else{ map.drawMinimap(SpaceGame.WIDTH-Minimap.WIDTH-20, SpaceGame.HEIGHT- Minimap.HEIGHT-30); } } </code></pre> <p>And my "Render.class" if you need to study it:</p> <pre><code>package com.maestrum; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.image.BufferedImage; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import java.util.Random; public class Render implements Runnable{ public Graphics2D g2d; public double xScroll,yScroll; public int frames; public int fps; public long lastTime; public int[] pSequence = new int[40]; public SpaceGame game; public Entity trackedEntity; public Random rand; public Render(SpaceGame game, Graphics2D g){ this.game = game; this.g2d = g; this.rand = new Random(); for(int i = 0 ; i &lt; 40; i++){ pSequence[i] = rand.nextInt(15) + 1; } } @Override public void run() { renderLoop(); } public void renderLoop(){ while(true){ game.render(); if(System.currentTimeMillis() - lastTime &gt;= 1000){ fps = frames; frames = 0; lastTime = System.currentTimeMillis(); } frames++; } } public void renderPlanets(){ overlayImage(ImageHandler.background, 0, 0, 1.5); for(int i = 0 ; i &lt; 20; i++){ overlayImage(ImageHandler.planets[pSequence[i]/4][pSequence[i]%4], i * 400 - xScroll/pSequence[i], i * pSequence[i]*40 - yScroll/pSequence[i]*2, pSequence[i]); } } private class PlanetRenderer { } public void overlayString(String s, double x, double y, int fontSize, int colour){ drawString(s, x+xScroll, y+yScroll, fontSize, colour); } public void overlayRectangle(double x, double y, int xs, int ys, int colour){ drawRectangle(x+xScroll, y+yScroll, xs, ys, colour); } public void overlayBlurred(BufferedImage img, double x, double y, double scale){ drawImageBlurred(img, x+xScroll, y+yScroll, scale); } public void overlayImage(BufferedImage img, double x, double y, double scale){ drawImage(img, x+xScroll, y+yScroll, scale); } public BufferedImage execute(BufferedImage img) { // TODO Auto-generated method stub float weight = 1.0f/2.0f; float [] elements = {weight, weight, weight, weight, weight, weight, weight, weight, weight}; Kernel k = new Kernel (3,3,elements); ConvolveOp op = new ConvolveOp(k); BufferedImage dest = new BufferedImage(img.getWidth(), img.getHeight(), img.getType()); op.filter(img, dest); return dest; } public void drawImageBlurred(BufferedImage img, double x, double y, double scale){ x -= xScroll; y -= yScroll; BufferedImage image = new BufferedImage((int)(img.getWidth()*scale), (int)(img.getHeight()*scale), BufferedImage.TYPE_INT_ARGB); Graphics g = image.getGraphics(); g.drawImage(img, 0, 0, (int)(img.getWidth()*scale), (int)(img.getHeight()*scale), null); execute(image); g2d.drawImage(image, (int)x, (int)y, null); g.dispose(); } public void drawString(String s, Vector2D pos, int fontSize, int colour){ drawString(s, pos.x, pos.y, fontSize, colour); } public void drawString(String s, double x, double y, int fontSize, int colour){ if(s == null){ return; } x -= xScroll; y -= yScroll; BufferedImage img = new BufferedImage(s.length()*fontSize+1, fontSize*2, BufferedImage.TYPE_INT_ARGB); Graphics g = img.getGraphics(); g.setColor(new Color(colour)); g.setFont(new Font("Consolas", Font.BOLD, fontSize)); g.drawString(s, 0, img.getHeight()/2); g2d.drawImage(img, (int)x, (int)y, null); g.dispose(); } public void drawImage(BufferedImage img, Vector2D pos, double scale){ drawImage(img, pos.x, pos.y, scale); } public void drawLine(Vector2D v1, Vector2D v2, int colour, int width){ drawLine(v1.x, v1.y, v2.x, v2.y, colour, width); } public void drawLine(double x1, double y1, double x2, double y2, int colour, int lWidth){ x1 -= xScroll; y1 -= yScroll; x2 -= xScroll; y2 -= yScroll; g2d.setColor(new Color(colour)); g2d.setStroke(new BasicStroke(lWidth)); g2d.drawLine((int)x1, (int)y1, (int)x2, (int)y2); } public void drawImage(BufferedImage img, double x, double y, double scale){ x -= xScroll; y -= yScroll; BufferedImage image = new BufferedImage((int)(img.getWidth()*scale), (int)(img.getHeight()*scale), BufferedImage.TYPE_INT_ARGB); Graphics g = image.getGraphics(); g.drawImage(img, 0, 0, (int)(img.getWidth()*scale), (int)(img.getHeight()*scale), null); g2d.drawImage(image, (int)x, (int)y, null); g.dispose(); } public void drawRectangle(Vector2D pos, int xs, int ys, int colour){ drawRectangle(pos.x, pos.y, xs, ys, colour); } public void drawRectangle(double x, double y, int xs, int ys, int colour){ if(xs &lt;= 0){ return; } x -= xScroll; y -= yScroll; BufferedImage image = new BufferedImage(xs, ys, BufferedImage.TYPE_INT_RGB); Graphics2D g = (Graphics2D) image.getGraphics(); g.setColor(new Color(colour)); g.fillRect(0, 0, xs, ys); g2d.drawImage(image, (int)x, (int)y, null); g.dispose(); } public void drawImageRotated(BufferedImage img, Vector2D pos, double scale, double angle) { drawImageRotated(img, pos.x, pos.y, scale, angle); } public void drawImageRotated(BufferedImage img, double x, double y, double scale, double angle) { x -= xScroll; y -= yScroll; BufferedImage image = new BufferedImage((int)(img.getWidth() * 1.5D), (int)(img.getHeight() * 1.5D), 2); Graphics2D g = (Graphics2D)image.getGraphics(); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.rotate(Math.toRadians(angle), image.getWidth() / 2, image.getHeight() / 2); g.drawImage(img, image.getWidth() / 2 - img.getWidth() / 2, image.getHeight() / 2 - image.getHeight() / 2, null); g2d.drawImage(image, (int)(x-image.getWidth()*scale/2), (int)(y-image.getHeight()*scale/2), (int)(image.getWidth()*scale), (int)(image.getHeight()*scale), null); g.dispose(); } </code></pre> <p>}</p> <p>As you can see in the rendering class, the render process is done as many times a second as possible. This is to give the game the highest possible FPS. If you missed the point of what I'm asking; What good practices should I take into account when rendering stuff using Java? And, what could possibly be causing the space ships health bar to render like so?</p> <p>NOTE: take a look at this video, I ran that program and got 80FPS with 50000 particles, however with my rendering code (which is obviously of a much lower quality) I can render only a mere 100 or so particles, before things start messing up.</p> <p><a href="http://www.youtube.com/watch?v=6M3Ze4Eu87Y" rel="noreferrer">http://www.youtube.com/watch?v=6M3Ze4Eu87Y</a></p> <p>This is my tick() function, it gets called every game tick (10ms)</p> <pre><code>public void tick(){ if(System.currentTimeMillis() - lastTime &gt;= 1000){ fps = frames; frames = 0; lastTime = System.currentTimeMillis(); } frames++; if(renderer.trackedEntity != null){ renderer.xScroll = renderer.trackedEntity.pos.x-SpaceGame.WIDTH/2; renderer.yScroll = renderer.trackedEntity.pos.y-SpaceGame.HEIGHT/2; } if(level != null &amp;&amp; !paused){ level.tick(); } if(currentGui != null &amp;&amp; currentGui.pausesGame()){ paused = true; }else{ paused = false; } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload