• Advertisement
Sign in to follow this  

Get object position

This topic is 429 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,

 

I'm beginner in opengl and I try to make a 2D snake game.So here is my code:

#include <iostream>

//GLEW
#define GLEW_STATIC
#include<glew.h>

//GLFW
#include <glfw3.h>
#include <SOIL.h>
#include "Shader.h"
// GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/type_ptr.hpp>

// Functions prototype
void key_callback(GLFWwindow *window, int key, int scancode, int action, int mode);
void mouse_callback(GLFWwindow* window, double xpos, double ypos);
void checkMovement();
void checkCollision(GLfloat xoffset, GLfloat yoffset, GLfloat &xfruitPos, GLfloat &yfruitPos);

// Window Dimensions
const GLuint screenWidth = 1000, screenHeight = 800;

bool keys[1024];


GLfloat deltaTime = 0.0f;
GLfloat lastFrame = 0.0f;



bool up = true;
bool left = false;
bool right = false;
bool down = false;

glm::vec3 cameraPos(0.0f, 0.0f, 6.0f);

GLfloat sensitivity = 0.0001f;
GLfloat xoffset = 0.0000f;
GLfloat yoffset = 0.0000f;
GLfloat xfruitPos = 0.0002f;
GLfloat yfruitPos = 0.0002f;
glm::vec3 position(0.0f, 0.0f, 0.0f);

int main()
{
	std::cout << "Starting GLFW context, OpenGL 3.3" << std::endl;

	// GLFW init
	glfwInit();
	// Set all the required options for GLFW
	glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
	glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
	glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
	glfwWindowHint(GLFW_RESIZABLE, GL_FALSE);

	// Create a GLFWWindow object that we can use for GLFW's functions
	GLFWwindow* window = glfwCreateWindow(screenWidth, screenHeight, "Snake OpenGL", nullptr, nullptr);
	if (window == nullptr)
	{
		std::cout << "Failed to create GLFW window" << std::endl;
		glfwTerminate();
	}
	glfwMakeContextCurrent(window);

	// Set the required callback functions
	glfwSetKeyCallback(window, key_callback);
	glfwSetCursorPosCallback(window, mouse_callback);
	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);

	// Set this to true so GLEW knows to use a modern approach to retrieving function pointers and extensions
	glewExperimental = GL_TRUE;
	glewInit();

	// Initialize GLEW to setup the OpenGL Function pointers
	if (glewInit() != GLEW_OK)
	{
		std::cout << "Failed to initialize GLEW" << std::endl;
		return -1;
	}
	int width, height;

	glfwGetFramebufferSize(window, &width, &height);

	// Define the viewport dimensions
	glViewport(0, 0, screenWidth, screenHeight);

	Shader headShader("headShader.vs", "headShader.frag");
	Shader groundShader("headShader.vs", "groundShader.frag");
	Shader fruitShader("headShader.vs", "fruitShader.frag");

	GLfloat vertices[] = {
		0.5f,  0.5f, 0.0f, 1.0f, 1.0f,
		0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
		-0.5f, -0.5f, 0.0f, 0.0f, 0.0f,
		-0.5f,  0.5f, 0.0f, 0.0f, 1.0f
	};

	GLuint indices[] = {
		0, 1, 3,
		1, 2, 3

	};


	GLuint headTexture, groundTexture;
	GLuint VBO, HEAD, EBO, GROUND, FRUIT;

	glGenVertexArrays(1, &HEAD);
	glGenVertexArrays(1, &GROUND);
	glGenVertexArrays(1, &FRUIT);

	glGenBuffers(1, &VBO);
	glGenBuffers(1, &EBO);

	// HEAD VAO
	glBindVertexArray(HEAD);
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
		// Set the vertex attrib pointers
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
		glEnableVertexAttribArray(0);
		// Set the texture attrib pointers
		glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
		glEnableVertexAttribArray(1);

		glBindBuffer(GL_ARRAY_BUFFER, 0);
	glBindVertexArray(0);


	// Head texture========================================
	glGenTextures(1, &headTexture);
		glBindTexture(GL_TEXTURE_2D, headTexture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	// Set texture wrapping to GL_REPEAT
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		// Set texture filtering
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		int imgWidth, imgHeight;
		unsigned char* image = SOIL_load_image("images/metal.png", &imgWidth, &imgHeight, 0, SOIL_LOAD_RGB);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imgWidth, imgHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
		glGenerateMipmap(GL_TEXTURE_2D);
		SOIL_free_image_data(image);
	glBindTexture(GL_TEXTURE_2D, 0);


	//GROUND VAO============================================================
	glBindVertexArray(GROUND);
		glBindBuffer(GL_ARRAY_BUFFER, VBO);

		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
		// Set the vertex attrib pointers
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
		glEnableVertexAttribArray(0);
		// Set the texture attrib pointers
		glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat)));
		glEnableVertexAttribArray(1);
	glBindVertexArray(0);


	// Ground texture==================================================
	glGenTextures(1, &groundTexture);
		glBindTexture(GL_TEXTURE_2D, groundTexture);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	// Set texture wrapping to GL_REPEAT
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
		// Set texture filtering
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
		image = SOIL_load_image("images/ground.jpg", &imgWidth, &imgHeight, 0, SOIL_LOAD_RGB);
		glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imgWidth, imgHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
		glGenerateMipmap(GL_TEXTURE_2D);
		SOIL_free_image_data(image);
	glBindTexture(GL_TEXTURE_2D, 0);

	
	// FRUIT VAO
	glBindVertexArray(FRUIT);
		glBindBuffer(GL_ARRAY_BUFFER, VBO);
		glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
		glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
		// Set the vertex attrib pointers
		glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
		glEnableVertexAttribArray(0);
	glBindVertexArray(0);


	// Game Loop
	while (!glfwWindowShouldClose(window))
	{

		GLfloat currentFrame = glfwGetTime();
		deltaTime = currentFrame - lastFrame;
		lastFrame = currentFrame;

		//Check if any events have been activated(key pressed, mouse moved etc.) and call corresponding response functions
		glfwPollEvents();


		// Render
		// Clear the color buffer
		glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
		glClear(GL_COLOR_BUFFER_BIT);
		

		// Ground SHADER PROGRAM
		groundShader.Use();
		glm::mat4 model;
		glm::mat4 view;
		glm::mat4 proj;

		view = glm::lookAt(cameraPos, glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 1.0f, 0.0f));
		proj = glm::perspective(45.0f, (float)screenWidth / (float)screenHeight, 0.1f, 100.0f);
		model = glm::translate(model, glm::vec3(0.0f, 0.0f, 3.0f));
		model = glm::scale(model, glm::vec3(4.0f, 4.0f, 4.0f));
		GLint modelLoc = glGetUniformLocation(headShader.Program, "model");
		GLint viewLoc = glGetUniformLocation(headShader.Program, "view");
		GLint projLoc = glGetUniformLocation(headShader.Program, "projection");
		glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));

		glBindTexture(GL_TEXTURE_2D, groundTexture);
		glUniform1i(glGetUniformLocation(groundShader.Program, "groundTexture"), 0);
		glBindVertexArray(GROUND);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glBindVertexArray(0);


		//FRUIT SHADER PROGRAM
		fruitShader.Use();

		model = glm::mat4();
		model = glm::translate(model, glm::vec3(xfruitPos, yfruitPos, 0.0f));
		model = glm::scale(model, glm::vec3(0.25f, 0.25f, 0.25f));
		modelLoc = glGetUniformLocation(headShader.Program, "model");
		viewLoc = glGetUniformLocation(headShader.Program, "view");
		projLoc = glGetUniformLocation(headShader.Program, "projection");
		glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));
	
		

		glBindVertexArray(FRUIT);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glBindVertexArray(0);

		checkCollision(xoffset, yoffset, xfruitPos, yfruitPos);
		//HEAD SHADER PROGRAM
		headShader.Use();

		// MODEL MATRIX
		model = glm::mat4();
		model = glm::translate(model, glm::vec3(xoffset, yoffset, 0.0f));
		model = glm::scale(model, glm::vec3(0.25f, 0.25f, 0.25f));
		position = (glm::vec3) model[3];
		modelLoc = glGetUniformLocation(headShader.Program, "model");
		viewLoc = glGetUniformLocation(headShader.Program, "view");
		projLoc = glGetUniformLocation(headShader.Program, "projection");
		glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
		glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
		glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(proj));

		glBindTexture(GL_TEXTURE_2D, headTexture);
		glUniform1i(glGetUniformLocation(headShader.Program, "ourTexture"), 0);
		glBindVertexArray(HEAD);
		glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
		glBindVertexArray(0);

		checkMovement();


		glfwSwapBuffers(window);
	}
	glDeleteVertexArrays(1, &HEAD);
	glDeleteVertexArrays(1, &GROUND);
	glDeleteVertexArrays(1, &FRUIT);
	glDeleteBuffers(1, &VBO);
	glDeleteBuffers(1, &EBO);

	glfwTerminate();
	return 0;
}


void key_callback(GLFWwindow *window, int key, int scancode, int action, int mode)
{
	
	if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
		glfwSetWindowShouldClose(window, GL_TRUE);

/*	if (key >= 0 && key < 1024)
	{
		if (action == GLFW_PRESS)
			keys[key] = true;
		else if (action == GLFW_RELEASE)
			keys[key] = false;
	}
	*/
	if (key == GLFW_KEY_W && action == GLFW_PRESS)
	{
		up = true;
		down = false;
		left = false;
		right = false;
	}
	if (key == GLFW_KEY_S && action == GLFW_PRESS)
	{
		up = false;
		down = true;
		left = false;
		right = false;
	}
	if (key == GLFW_KEY_D && action == GLFW_PRESS)
	{
		up = false;
		down = false;
		left = false;
		right = true;
	}
	if (key == GLFW_KEY_A && action == GLFW_PRESS)
	{
		up = false;
		down = false;
		left = true;
		right = false;
	}

	
}

void checkMovement()
{
	if (up)
	{
		yoffset += sensitivity;
		if (yoffset == 1.0f)
		{
			std::cout << "DONE" << std::endl;
		}
	}
	if (down)
	{
		yoffset -= sensitivity;
		if (yoffset == 1.0f)
		{
			std::cout << "DONE" << std::endl;
		}
	}
	if (right)
	{
		xoffset += sensitivity;
		if (xoffset == 1.0f)
		{
			std::cout << "DONE" << std::endl;
		}
	}
	if (left)
	{
		xoffset -= sensitivity;
		if (xoffset == 1.0f)
		{
			std::cout << "DONE" << std::endl;
		}
	}
	std::cout << std::endl;
}

void mouse_callback(GLFWwindow* window, double xpos, double ypos)
{
	
}

void checkCollision(GLfloat xoffset, GLfloat yoffset, GLfloat &xfruitPos, GLfloat &yfruitPos)
{
	if ((xoffset == xfruitPos) && (yoffset == yfruitPos))
	{
		xfruitPos++;
		std::cout << "fruitPos.X: " << xfruitPos << std::endl;
		yfruitPos++;
		std::cout << "fruitPos.Y: " << yfruitPos << std::endl;
		std::cout << std::endl;
	}
}

If I give the initial positions to fruit and snake the same, and I calculate if they are equal(on checkCollision function), is generating the fruit in another position(so it works).But when I move with the snake on fruit's new position it doesn't work anymore.Where am I wrong ? It's because the floating values or ... ?
I would be very happy if somebody can help me.
P.S: Ignore for the moment the ugly code! biggrin.gif
Thank you! 

Share this post


Link to post
Share on other sites
Advertisement

you are checking if floats are EXACTLY equal.  If you are doing operations on floating point numbers (i.e. you are adding a fractional float to the floats) then do to the way floats works and their inaccuracy, it is not surprising you are not finding them exactly equal even when they should be when you write the computation down on paper.

 

you start with an xoffset and yoffset set to some value.  on a keypress you are adding the sensitivity value to them which is 0.0001f.  You are assuming after enough of those it will equal EXACTLY the float position you set for the fruit.  If you print out the values for your xoffset and yoffset you will probably see it is very slightly off from what you expect when you are comparing it to the fruits position.  So if fruit was say 1.0f, 1.0f then your xoffset and yoffset may end up being 1.0000000000001f, 1.000000000001f after you do floating point operations on it.

 

do something instead like:

a = abs(fruitx - xoffset)

if (a < threshold)

   collision;

Share this post


Link to post
Share on other sites

Hi,

 

Thank you for your reply.

Yes, I figured this after I used the debugger.:D.I will try what you told me.

After this I will want to grow my snake.I know(somehow) how to make it.But I would like, if you or somebody else can, to give me an advice about how to manage the code(with classes, how to manage the buffers..etc).

Thanks again!

Share this post


Link to post
Share on other sites

snake can be done with a list of body parts basically.  you have a head and an array of body.  you control the direction/position of the head with the controls of your game.  then the other body parts just move to where the one before it was

 

// init

vector<SnakePart> parts;

parts.push_back(head)

parts.push_back(body0)

parts.push_back(body1)

parts.push_back(body2)

 

// draw

for (auto& p : parts)

    p.draw()

 

 

// update

moveheadwithcontrols(parts[0])

for (int i = 1; i < parts.size(); ++i)

     move_part_to_where_the_other_part_was(parts, parts[i-1])

Share this post


Link to post
Share on other sites

Is there another way to manipulate the snake body without using arrays/vectors/lists ?
 

 

Certainly, but ultimately you need something to store the data.  Those structures work quite well.  Do have an aversion to them, or have some other data structure you think would be a better fit?

Share this post


Link to post
Share on other sites

Not really, you need to keep the position of each segment somewhere, and a list or vector of segments is the simplest solution to that (vector more than list, in C/C++).

Is there anything in particular that bothers you with vectors or lists?

 

You can reduce the amount of work that you need to do with each move by using a round-robin buffer, but I think that highly complicates extending the snake one segment when it eats fruit, so better not do that.

 

 

As for your structure, the main() function is quite long, splitting that could be useful. I can't see quickly how all the dependencies run, but I'd start with making a few functions to reduce the number of lines in main(). If you find that functions share a lot of data, you could move that data and all the functions to a separate class.

 

Make a copy as backup, and try things. If you like where it's going, keep the new version. If it gets too complicated or you don't like it, discard the changes by going back to the previous backupped version. I also often do such quick experiments to see how things are connected, although my "quick" is a lot slower than yours, due to the size of the program :)

Share this post


Link to post
Share on other sites

Thank you guys for your reply.

@Alberth: To be honestly, for the moment, working with vectors and lists bothers me a little bit, because I'm a beginner in openGL and c++. :rolleyes: I know c++, theoretical, but practically, I don't have so much experience to work with it. I know how to make console programs with vectors etc. but not when it comes to applications like snake. :D.(I have to break up this fear about working with vectors) .

 

The first thing I wanted to do was to make the snake working and after to come back and split the code in the main.:P. I can do a few functions, but I don't know if I would work with classes what to put in these classes.Maybe I could use your advice.

 

Btw, you said to work with vectors / lists. It would be ok to make someting like: vector<glm::vec3> positions, to keep the body's positions ?

 

Thank you very much again! :)

Share this post


Link to post
Share on other sites
I know how to make console programs with vectors etc. but not when it comes to applications like snake.

vectors don't care if the output is to an OpenGL device, they work the same in every case. Just pretend you're outputting to console, except in the code that deals with OpenGL :)

 

 

 

It would be ok to make someting like: vector positions<glm::vec3>, to keep the body's positions ?

:o   3D snake game?

But sure, at least in theory that should work. The only thing I don't know is whether you can change the x&y coordinates of a glm::vec3 object. You must update the position of the segments each time, which means you must modify x & y.

 

Alternatively, writing a simple class yourself works too

class XY {
public:
    XY(int x, int y) : x(x), y(y) { }

    int x;
    int y;
};

std::vector<XY> segments;

If you like getters and setters, you could add those too.

Edited by Alberth

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement